using System;
using System.Collections.Generic;
using Message;
using UnityEngine;

namespace LFromeWork
{
    public class SocketManager : IDisposable
    {
        [Header("每帧最大发送数量")]
        public int MaxSendCount = 5;

        [Header("每次发包最大的字节")]
        public int MaxSendByteCount = 1024;

        [Header("每帧最大处理包数量")]
        public int MaxReceiveCount = 5;

        [Header("心跳间隔")]
        public int HeartbeatInterval = 10;

        /// <summary>
        /// 上次心跳时间
        /// </summary>
        private float m_PrevHeartbeatTime = 0;

        /// <summary>
        /// PING值(毫秒)
        /// </summary>
        public int PingValue;

        /// <summary>
        /// 游戏服务器的时间
        /// </summary>
        public long LastServerTime;

        /// <summary>
        /// 是否已经连接到主Socket
        /// </summary>
        private bool m_IsConnectToMainSocket = false;

        /// <summary>
        /// 发送用的MS
        /// </summary>
        public MMO_MemoryStream SocketSendMS
        {
            get;
            private set;
        }

        /// <summary>
        /// 接收用的MS
        /// </summary>
        public MMO_MemoryStream SocketReceiveMS
        {
            get;
            private set;
        }

        /// <summary>
        /// SocketTcp访问器链表
        /// </summary>
        private LinkedList<SocketTcpRoutine> m_SocketTcpRoutineList;

        public SocketManager()
        {
            m_SocketTcpRoutineList = new LinkedList<SocketTcpRoutine>();
            SocketSendMS = new MMO_MemoryStream();
            SocketReceiveMS = new MMO_MemoryStream();
        }

        /// <summary>
        /// 初始化
        /// </summary>
        public void Init()
        {
            m_MainSocket = CreateSocketTcpRoutine();
            GameLaunch.Event.SocketEvent.AddEventListener(ProtoId.SHeartbeat1,ReceiveHeartbeatMsg);
        }

        /// <summary>
        /// 创建SocketTcp访问器
        /// </summary>
        /// <returns></returns>
        public SocketTcpRoutine CreateSocketTcpRoutine()
        {
            //从池中获取（什么时候回池）
            return new SocketTcpRoutine();
        }

        /// <summary>
        /// 注册SocketTcp访问器
        /// </summary>
        /// <param name="routine"></param>
        internal void RegisterSocketTcpRoutine(SocketTcpRoutine routine)
        {
            m_SocketTcpRoutineList.AddFirst(routine);
        }

        /// <summary>
        /// 移除SocketTcp访问器
        /// </summary>
        /// <param name="routine"></param>
        internal void RemoveSocketTcpRoutine(SocketTcpRoutine routine)
        {
            m_SocketTcpRoutineList.Remove(routine);
        }

        internal void OnUpdate()
        {
            for (LinkedListNode<SocketTcpRoutine> curr = m_SocketTcpRoutineList.First; curr != null; curr = curr.Next)
            {
                curr.Value.OnUpdate();
            }

            SendHeartbeatMsg();
        }

        /// <summary>
        /// 主Socket
        /// </summary>
        private SocketTcpRoutine m_MainSocket;

        /// <summary>
        /// 连接主Socket
        /// </summary>
        /// <param name="ip"></param>
        /// <param name="port"></param>
        public void ConnectToMainSocket(string ip, int port, Action<bool> onConnectComplete)
        {
            m_MainSocket.Connect(ip, port, (bool result) =>
            {
                onConnectComplete?.Invoke(result);
                m_IsConnectToMainSocket = true;
            });
        }

        /// <summary>
        /// 发送心跳消息
        /// </summary>
        /// <param name="buffer"></param>
        public void SendHeartbeatMsg()
        {
            if (m_IsConnectToMainSocket)
            {
                if (Time.realtimeSinceStartup > m_PrevHeartbeatTime + HeartbeatInterval)
                {
                    //发送心跳
                    m_PrevHeartbeatTime = Time.realtimeSinceStartup;

                    CHeartbeat0 proto = new CHeartbeat0();
                    proto.Time = DateTime.UtcNow.Ticks;
                    proto.Ping = PingValue;
                    m_MainSocket.SendMsg(proto);
                }
            }
        }
        
        /// <summary>
        /// 接收心跳消息
        /// </summary>
        /// <param name="buffer"></param>
        public void ReceiveHeartbeatMsg(byte[] buffer)
        {
            SHeartbeat1 proto = SHeartbeat1.Parser.ParseFrom(buffer);
            PingValue = (int)((DateTime.UtcNow.Ticks - proto.Time) * 0.5f / 10000) + proto.ToGameServerPing;
            LastServerTime = proto.ServerTime;
        }

        public void Dispose()
        {
            m_SocketTcpRoutineList.Clear();

            m_IsConnectToMainSocket = false;

            m_MainSocket.DisConnect();
            GameLaunch.Event.SocketEvent.RemoveEventListener(ProtoId.SHeartbeat1,ReceiveHeartbeatMsg);

            SocketSendMS.Dispose();
            SocketReceiveMS.Dispose();

            SocketSendMS.Close();
            SocketReceiveMS.Close();
        }
    }
}